/**
 * Copyright (C) 2018-2020
 * All rights reserved, Designed By www.yixiang.co
 * 注意：
 * 本软件为www.yixiang.co开发研制，未经购买不得使用
 * 购买后可获得全部源代码（禁止转卖、分享、上传到码云、github等开源平台）
 * 一经发现盗用、分享等行为，将追究法律责任，后果自负
 */
package co.yixiang.modules.auth.rest;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import co.yixiang.api.ApiResult;
import co.yixiang.api.YshopException;
import co.yixiang.common.aop.NoRepeatSubmit;
import co.yixiang.common.bean.LocalUser;
import co.yixiang.common.enums.SmsTypeEnum;
import co.yixiang.common.interceptor.AuthCheck;
import co.yixiang.common.util.JwtToken;
import co.yixiang.common.util.SmsUtil;
import co.yixiang.common.util.SmsUtils;
import co.yixiang.constant.ShopConstants;
import co.yixiang.enums.ShopCommonEnum;
import co.yixiang.modules.auth.param.*;
import co.yixiang.modules.services.AuthService;
import co.yixiang.modules.user.domain.YxUser;
import co.yixiang.modules.user.domain.YxUserinfo;
import co.yixiang.modules.user.service.YxUserService;
import co.yixiang.modules.user.service.YxUserinfoService;
import co.yixiang.utils.*;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @ClassName 认证服务
 * @Author hupeng <610796224@qq.com>
 * @Date 2020/4/30
 **/
@Slf4j
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Api(value = "认证模块", tags = "商城:认证", description = "认证")
public class AuthController {

    private final YxUserService userService;
    private final YxUserinfoService userinfoService;
    private final RedisUtils redisUtil;
    private final AuthService authService;

    @Value("${single.login}")
    private Boolean singleLogin;



    @ApiOperation("小程序登录")
    @PostMapping(value = "/appletLogin")
    public ApiResult<Map<String, Object>> login(@Validated @RequestBody AppletParam appletParam,
                                                HttpServletRequest request) {

        appletParam = analysisCode(appletParam);

        YxUser user = userService.getOne(Wrappers.<YxUser>lambdaQuery()
                .eq(YxUser::getOpenId,appletParam.getOpenId()),false);
        if (ObjectUtil.isEmpty(user)) {
            //注册
            user = authService.appletRegister(appletParam);
        }
        String token =  JwtToken.makeToken(user.getUid());
        String expiresTimeStr = JwtToken.getExpireTime(token);
        // 保存在线信息
        authService.save(user, token, request);

        boolean empty = ObjectUtil.isNotEmpty(user.getReferralCode());
        // 返回 token
        Map<String, Object> map = new HashMap<String, Object>(3) {{
            put("token", token);
            put("isSuperiors" , empty);
            put("expires_time", expiresTimeStr);
        }};

        if(singleLogin){
            //踢掉之前已经登录的token
            if (ObjectUtil.isNotEmpty(user.getUsername())) authService.checkLoginOnUser(user.getUsername(),token);
        }
        return ApiResult.ok(map).setMsg("登陆成功");
    }


    private AppletParam analysisCode(AppletParam appletParam){
        String serviceAddress = "https://api.weixin.qq.com/sns/jscode2session?appid=wx540287f578e8f072&secret=64cc272c9cb4253ece62a593a6921100&js_code="
                + appletParam.getCode() + "&grant_type=authorization_code";
        Map<String, Object> map = new HashMap<>();
        try {
            map = VerifyUtil.sendGet(serviceAddress);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(map);
        JSONObject jsonObject = JSONObject.parseObject(String.valueOf(map.get("entity")));
        appletParam.setOpenId(jsonObject.getString("openid"));
        return appletParam;
    }


    @AuthCheck
    @NoRepeatSubmit
    @ApiOperation("绑定邀请码")
    @GetMapping(value = "/bindingCode")
    public ApiResult bindingCode(@RequestParam(value = "referralCode" , required = false) String referralCode) {
        YxUser user = LocalUser.getUser();
        Optional.ofNullable(referralCode).orElseThrow(() -> new YshopException("邀请码为空"));
//        authService.bindingCode(user , referralCode);
        return ApiResult.ok().setMsg("绑定成功");
    }


    @AuthCheck
    @NoRepeatSubmit
    @ApiOperation("绑定手机号")
    @PostMapping(value = "/bindingPhone")
    public ApiResult bindingPhone(@Validated @RequestBody BindingPhoneParam bindingPhoneParam
            , HttpServletRequest request) {
        YxUser user = LocalUser.getUser();

        Object codeObj = redisUtil.get("code_" + bindingPhoneParam.getAccount());
        if(codeObj == null){
            return ApiResult.fail("请先获取验证码");
        }
        String code = codeObj.toString();
        if (!StrUtil.equals(code, bindingPhoneParam.getCaptcha())) {
            return ApiResult.fail("验证码错误");
        }


        if (ObjectUtil.isNotEmpty(user.getUsername())) throw new YshopException("当前账户已绑定手机号");
        YxUser user1 = this.userService.getOne(new QueryWrapper<YxUser>().lambda()
                .eq(YxUser::getUsername, bindingPhoneParam.getAccount()));
        if (ObjectUtil.isNotEmpty(user1)){
            if (ObjectUtil.isNotEmpty(user1.getOpenId())) throw new YshopException("当前账户已绑定小程序");
            //塞openId
            user1.setOpenId(user.getOpenId());
            this.userService.updateById(user1);
            //删除此账户  ||  用户信息
            this.userService.removeById(user.getUid());

            this.userinfoService.remove(new QueryWrapper<YxUserinfo>().lambda()
                    .eq(YxUserinfo::getUid , user.getUid()));
            //移数据
            user = user1;
        }else {
            Optional.ofNullable(bindingPhoneParam.getReferralCode()).orElseThrow(() -> new YshopException("邀请码为空"));

            authService.bindingCode(user , bindingPhoneParam.getAccount() , bindingPhoneParam.getReferralCode());
        }



        String token =  JwtToken.makeToken(user.getUid());
        String expiresTimeStr = JwtToken.getExpireTime(token);
        // 保存在线信息
        authService.save(user, token, request);

        boolean empty = ObjectUtil.isNotEmpty(user.getReferralCode());
        // 返回 token
        Map<String, Object> map = new HashMap<String, Object>(3) {{
            put("token", token);
            put("isSuperiors" , empty);
            put("expires_time", expiresTimeStr);
        }};

        if(singleLogin){
            //踢掉之前已经登录的token
            if (ObjectUtil.isNotEmpty(user.getUsername())) authService.checkLoginOnUser(user.getUsername(),token);
        }

        return ApiResult.ok(map).setMsg("绑定成功");
    }



    @ApiOperation("H5登录授权")
    @PostMapping(value = "/login")
    public ApiResult<Map<String, Object>> login(@Validated @RequestBody HLoginParam loginDTO,HttpServletRequest request) {
        YxUser yxUser = userService.getOne(Wrappers.<YxUser>lambdaQuery()
                .eq(YxUser::getUsername,loginDTO.getUsername())
                .eq(YxUser::getPassword,SecureUtil.md5(loginDTO.getPassword())),false);

        if(yxUser == null) throw new YshopException("账号或者密码不正确");
        if(1 == yxUser.getIsFreeze()) throw new YshopException("该账号已被冻结");

        //验证码
//        Object codeObj = redisUtil.get("code_" + yxUser.getUsername());
//        String code = codeObj.toString();
//        if (!StrUtil.equals(code, loginDTO.getCode())) {
//            throw new YshopException("验证码错误");
//        }
        String token =  JwtToken.makeToken(yxUser.getUid());
        String expiresTimeStr = JwtToken.getExpireTime(token);
        yxUser.setClientId(loginDTO.getClientId());
        // 保存在线信息
        authService.save(yxUser, token, request);
        // 返回 token
        Map<String, Object> map = new HashMap<String, Object>(2) {{
            put("token", token);
            put("expires_time", expiresTimeStr);
        }};

        userService.setSpread(loginDTO.getSpread(),yxUser.getUid());

        if(singleLogin){
            //踢掉之前已经登录的token
            authService.checkLoginOnUser(yxUser.getUsername(),token);
        }

     //   redisUtil.del("code_" + yxUser.getUsername());
        return ApiResult.ok(map).setMsg("登陆成功");
    }


    @PostMapping("/register")
    @ApiOperation(value = "H5/APP注册新用户", notes = "H5/APP注册新用户")
    public ApiResult<String> register(@Validated @RequestBody RegParam param) {
        int count = userService.count(new QueryWrapper<YxUser>().lambda());
        if (count >= 10000) throw new YshopException("平台限制人数10000人");

        Object codeObj = redisUtil.get("code_" + param.getAccount());
        if(codeObj == null){
            return ApiResult.fail("请先获取验证码");
        }
        String code = codeObj.toString();
        if (!StrUtil.equals(code, param.getCaptcha())) {
            return ApiResult.fail("验证码错误");
        }
        YxUser yxUser = userService.getOne(Wrappers.<YxUser>lambdaQuery()
                .eq(YxUser::getPhone,param.getAccount()),false);
        if (ObjectUtil.isNotNull(yxUser)) {
            return ApiResult.fail("用户已存在");
        }

        //判断密码不能小于8位数，并是数字字母组合
        String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,100}$";
        if(!param.getPassword().matches(regex))return ApiResult.fail("密码不能小于8位,并是数字字母组合");


        authService.register(param);
        redisUtil.del("code_" + param.getAccount());
        return ApiResult.ok("","注册成功");
    }

    @AuthCheck
    @PostMapping("/changePhone")
    @ApiOperation(value = "修改手机号", notes = "修改手机号")
    public ApiResult<String> changePhone(@Validated @RequestBody ChangePhoneParam param) {
        YxUser yxUser= LocalUser.getUser();
        Object codeObj1 = redisUtil.get("code_" + param.getBeforePhone());
        Object codeObj = redisUtil.get("code_" + param.getNowPhone());

        if(codeObj1 == null){
            return ApiResult.fail("请先获取原手机号验证码");
        }

        if(codeObj == null){
            return ApiResult.fail("请先获取现手机号验证码");
        }
        String code1 = codeObj1.toString();
        String code = codeObj.toString();

        if (!StrUtil.equals(code1, param.getBeforePhoneCode())) {
            return ApiResult.fail("原手机号验证码错误");
        }

        if (!StrUtil.equals(code, param.getCode())) {
            return ApiResult.fail("现手机号验证码错误");
        }
        if(!yxUser.getPhone().equals(param.getBeforePhone())){
            return ApiResult.fail("旧手机号输入错误");
        }
        YxUser yxUser1=userService.getOne(new QueryWrapper<YxUser>().lambda().eq(YxUser::getUsername,param.getNowPhone()));
        if(null==yxUser1){
            return ApiResult.fail("新手机号已被其他用户使用");
        }
        yxUser.setPhone(param.getNowPhone());
        yxUser.setUsername(param.getNowPhone());
        userService.updateById(yxUser);
        redisUtil.del("code_" + param.getBeforePhone());
        redisUtil.del("code_" + param.getNowPhone());
        return ApiResult.ok("","修改手机号成功");
    }

    @PostMapping("/forgetPwd")
    @ApiOperation(value = "忘记密码", notes = "忘记密码")
    public ApiResult<String> forgetPwd(@Validated @RequestBody ForgetPwdParam param) {
        Object codeObj = redisUtil.get("code_" + param.getPhone());
        if(codeObj == null){
            return ApiResult.fail("请先获取验证码");
        }
        String code = codeObj.toString();
        if (!StrUtil.equals(code, param.getCode())) {
            return ApiResult.fail("验证码错误");
        }
        YxUser yxUser = userService.getOne(Wrappers.<YxUser>lambdaQuery()
                .eq(YxUser::getPhone,param.getPhone()),false);
        if(null==yxUser){
            return ApiResult.fail("当前用户未注册");
        }

        //判断密码不能小于8位数，并是数字字母组合
        String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,100}$";
        if(!param.getPassword().matches(regex))return ApiResult.fail("密码不能小于8位,并是数字字母组合");

        yxUser.setPassword(SecureUtil.md5(param.getPassword()));
        userService.updateById(yxUser);
        redisUtil.del("code_" + param.getPhone());
        return ApiResult.ok("","密码修改成功");
    }
    @AuthCheck
    @PostMapping("/register/verification")
    @ApiOperation(value = "短信验证码验证", notes = "短信验证码发送")
    public ApiResult<String> verification(@RequestParam(value = "code" , required = false) String code) {
        YxUser yxUser=LocalUser.getUser();

        Object codeObj = redisUtil.get("code_" + yxUser.getUsername());
        String codes = codeObj.toString();
       if (!StrUtil.equals(code, codes)) {
           throw new YshopException("验证码错误");
       }
        redisUtil.del("code_" + yxUser.getUsername());
        return ApiResult.ok("验证成功！");
    }


    @PostMapping("/register/verify")
    @ApiOperation(value = "短信验证码发送", notes = "短信验证码发送")
    public ApiResult<String> verify(@Validated @RequestBody VerityParam param) {
        YxUser yxUser = userService.getOne(Wrappers.<YxUser>lambdaQuery()
                .eq(YxUser::getPhone,param.getPhone()),false);
        if (SmsTypeEnum.REGISTER.getValue().equals(param.getType()) && ObjectUtil.isNotNull(yxUser)) {
            return ApiResult.fail("手机号已注册");
        }
        if (SmsTypeEnum.LOGIN.getValue().equals(param.getType()) && ObjectUtil.isNull(yxUser)) {
            return ApiResult.fail("账号不存在");
        }
        String codeKey = "code_" + param.getPhone();

        String code = RandomStringUtils.randomStr();

        //redis存储
        redisUtil.set(codeKey, code, ShopConstants.YSHOP_SMS_REDIS_TIME);

        //发送阿里云短信
        JSONObject json = new JSONObject();
        json.put("code",code);
        try {
            FuseCloudSmsUtil.sendSms(param.getPhone() , FuseCloudSmsUtil.sign+"您的验证码是"+code+"。如非本人操作，请忽略本短信!");
          //  Sample.sendSms(param.getPhone(),code);
        } catch (Exception e) {
            redisUtil.del(codeKey);
            e.printStackTrace();
            return ApiResult.ok("发送失败："+e);
       }
        return ApiResult.ok("发送成功，请注意查收");
    }

    @AuthCheck
    @ApiOperation(value = "退出登录", notes = "退出登录")
    @PostMapping(value = "/auth/logout")
    public ApiResult<String> logout() {
       YxUser yxUser=LocalUser.getUser();
       yxUser.setClientId("");
        userService.updateById(yxUser);
        return ApiResult.ok("退出成功");
    }



    public static void main(String[] args){
        String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,100}$";
        String value = "1234we"; // 长度不够
        System.out.println(value.matches(regex));
    }

}
